from rest_framework import serializers
from rest_framework.generics import CreateAPIView
from rest_framework.generics import RetrieveAPIView
from rest_framework.generics import ListAPIView

from rest_framework.pagination import LimitOffsetPagination
from rest_framework.filters import BaseFilterBackend
from django.forms import model_to_dict
from django.db.models import F
from django.db.models import Max
from django.db import transaction
from api.utils.auth import GeneralAuthorization
from api import models

class NewsMinFilterBackend(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        min_id=request.query_params.get('min_id')
        if min_id:
            return queryset.filter(id__lt=min_id)
        else:
            return queryset

class NewsMaxFilterBackend(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        max_id=request.query_params.get('max_id')
        if max_id:
            return queryset.filter(id__gt=max_id)
        else:
            return queryset

class NewsLimitOffsetPagination(LimitOffsetPagination):
    '''
    切片分页
    '''
    default_limit = 10
    max_limit = 50
    limit_query_param = 'limit'
    offset_query_param = 'offset'

    def get_offset(self, request):
        return 0


class ListNewsModelSerializer(serializers.ModelSerializer):
    '''
    查看动态的序列化
    '''
    topic=serializers.SerializerMethodField()
    user=serializers.SerializerMethodField()

    class Meta:
        model=models.News
        exclude=['address',]

    def get_topic(self,obj):
        if not obj.topic:
            return
        return model_to_dict(obj.topic,['id','topic'])

    def get_user(self, obj):
        return model_to_dict(obj.user, ['id', 'nickname','avatar'])

class CreateNewsPicSerializer(serializers.Serializer):
    '''
    动态图片的验证序列化
    '''
    key=serializers.CharField()
    cos_path=serializers.CharField

class CreateNewsModelSerializer(serializers.ModelSerializer):
    '''
    发布动态的序列化
    '''
    image_list=CreateNewsPicSerializer(many=True)
    class Meta:
        model=models.News
        exclude=['user','viewer_count','comment_count','favor_count']

    def create(self, validated_data):
        with transaction.atomic():
            save_point=transaction.savepoint()
            try:

                image_list = validated_data.pop('image_list')
                news_obj = models.News.objects.create(**validated_data)

                data_list = models.NewsDetail.objects.bulk_create(
                    [models.NewsDetail(**info, news=news_obj) for info in image_list])
                news_obj.image_list = data_list
                if news_obj.topic:
                    models.Topic.objects.filter(id=news_obj.topic_id).update(count=F('count') + 1)
                transaction.savepoint_commit(save_point)
                return news_obj
            except Exception as e:
                transaction.savepoint_rollback(save_point)

class NewsView(CreateAPIView,ListAPIView):
    '''
    动态相关接口
        -查看动态
        -创建动态
    '''
    queryset=models.News.objects.prefetch_related('user','topic').order_by('-id')
    pagination_class = NewsLimitOffsetPagination
    filter_backends = [NewsMaxFilterBackend,NewsMinFilterBackend]

    def perform_create(self, serializer):

        new_obj=serializer.save(user_id=1)


    def get_serializer_class(self):
        if self.request.method == 'POST':
            return CreateNewsModelSerializer
        if self.request.method == 'GET':
            return ListNewsModelSerializer

class NewsOneSerializer(serializers.ModelSerializer):
    images=serializers.SerializerMethodField()
    create_date=serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S')
    user=serializers.SerializerMethodField()
    topic=serializers.SerializerMethodField()
    viewer=serializers.SerializerMethodField()
    comment_record=serializers.SerializerMethodField()
    is_favor=serializers.SerializerMethodField()

    class Meta:
        model=models.News
        # fields='__all__'
        exclude=['cover',]

    def get_images(self,obj):
        image_set=models.NewsDetail.objects.filter(news=obj)
        return [model_to_dict(item,['id','cos_path']) for item in image_set]

    def get_topic(self, obj):
        if obj.topic:
            return model_to_dict(obj.topic,['id','title'])
        else:
            return None
    def get_user(self,obj):
        return model_to_dict(obj.user, ['id', 'nickname','avatar'])

    def get_viewer(self,obj):
        vierwer_set=models.ViewerRecord.objects.filter(news=obj).order_by('-id')
        context={
            'count':vierwer_set.count(),
            'result':[model_to_dict(row.user,['id','avatar','nickname']) for row in vierwer_set[0:10]]
        }
        return context

    def get_comment_record(self,obj):
        first_depth_id_set=models.CommentRecord.objects.filter(news=obj,depth=1).order_by('id').values_list('pk')[0:10]
        second_depth_id_set=models.CommentRecord.objects.filter(news=obj,depth=2,reply_id__in=first_depth_id_set).values('reply_id').annotate(max_id=Max('id'))
        firs_queryset=models.CommentRecord.objects.filter(news=obj,depth=1).order_by('id').values('id','content','user__nickname','create_date')[0:10]

        second_queryset=models.CommentRecord.objects.filter(id__in=[item['max_id'] for item in second_depth_id_set]).values('id','reply_id','content','user__nickname','create_date')

        first_depth_dict={}
        for item in firs_queryset:

            first_depth_dict[item['id']]=item
            first_depth_dict[item['id']]['create_date'].strftime('%Y-%m-%d')
            first_depth_dict[item['id']]['child']=[]
        for item in second_queryset:

            item['create_date'].strftime('%Y-%m-%d')
            first_depth_dict[item['reply_id']]['child'].append(item)

        return first_depth_dict.values()

    def get_is_favor(self,obj):
        #1 用户是否登录
        user_obj= self.context['request'].user
        if not user_obj:
            return False
        exists=models.NewsFavorRecord.objects.filter(news=obj,user=user_obj).exists()
        if not exists:
            return False
        else:
            return True
class NewsOneApiView(RetrieveAPIView):

    queryset = models.News.objects
    serializer_class = NewsOneSerializer
    # authentication_classes = [GeneralAuthentication,]

    def get(self,request,*args,**kwargs):
        response=super().get(request, * args, ** kwargs)

        #用户没有登录
        if not request.user:
            return response
        #用户登录
        news_obj = self.get_object()
        #查看浏览记录是否有记录
        exists=models.ViewerRecord.objects.filter(news=news_obj,user=request.user).exists()
        if not exists:
            with transaction.atomic():
                models.ViewerRecord.objects.create(news=news_obj,user=request.user)
                models.News.objects.filter(news=news_obj).update(viewer_count=F('viewer_count')+1)
        return response

        #djang中获取认证token 的信息的

        # token=request.META.get('HTTP_AUTHORIZATION')
        # from rest_framework.request import Request
        # try:
        #     user_obj=models.UserInfo.objects.filter(token=token).first()
        #
        #     exists=models.ViewerRecord.objects.filter(news_id=kwargs['pk'],user=user_obj).exists()
        #
        #     if not exists:
        #         models.ViewerRecord.objects.create(news_id=kwargs['pk'],user=user_obj)
        #         models.News.objects.filter(pk=kwargs['pk']).update(viewer_count=F('viewer_count')+1)
        # except Exception as e:
        #     print(e)
        # res=super().get(request, * args, ** kwargs)
        # #如果用户登录 动态访问记录表添加访问记录
        # return res